#include "mem.h"
#include <iostream>
#include <cstring>

class Observer : public cnc::base::Observer
{
	cnc::base::GlobalData *globalData_;
public:
	Observer()
	{
		cnc::base::Memory *mem = cnc::base::getMemory();
		globalData_ = mem->getGlobalData();
	}
	void onSmile()
	{
		uint8_t value;
		cnc::base::Register *reg = globalData_->getRegister(":)");
		reg->get(&value);
		std::cout << static_cast<int>(value) << std::endl;
	}
	void onSad()
	{
		int32_t value;
		cnc::base::Register *reg = globalData_->getRegister(":(");
		reg->get(&value);
		std::cout << value << std::endl;
	}
	void onHappy()
	{
		double value;
		cnc::base::Register *reg = globalData_->getRegister(":D");
		reg->get(&value);
		std::cout << value << std::endl;
	}
	virtual void update(const char *registerID)
	{
		static const char *id[] = { ":)", ":(", ":D" };
		static const int size = sizeof(id) / sizeof(const char *);
		int option;
		for (option = 0; option < size; option++)
			if (strcmp(id[option], registerID) == 0)
				break;
		std::cout << "El nuevo valor de " << id[option] << " es ";
		switch (option) {
		case 0:
			onSmile();
			break;
		case 1:
			onSad();
			break;
		case 2:
			onHappy();
			break;
		}
	}
};


int main()
{
	cnc::base::Memory *mem = cnc::base::getMemory();
	if (mem == 0) {
		std::cout << "Error al cargar el módulo de memoria." << std::endl;
		return 1;
	}
	cnc::base::GlobalData *globalData = mem->getGlobalData();
	if (globalData == 0) {
		std::cout << "Error al los datos globales." << std::endl;
		return 1;
	}
	if (!globalData->addRegister(":)", cnc::base::DT_UINT8)) {
		std::cout << "No se puede agregar registro :)." << std::endl;
		return 1;
	}
	if (!globalData->addRegister(":(", cnc::base::DT_INT32)) {
		std::cout << "No se puede agregar registro :(." << std::endl;
		return 1;
	}
	if (!globalData->addRegister(":D", cnc::base::DT_FLOAT64)) {
		std::cout << "No se puede agregar registro :D." << std::endl;
		return 1;
	}
	Observer observer;
	if (!globalData->addObserver(":)", &observer)) {
		std::cout << "No se puede agregar observador para el registro :)." << std::endl;
		return 1;
	}
	if (!globalData->addObserver(":(", &observer)) {
		std::cout << "No se puede agregar observador para el registro :(." << std::endl;
		return 1;
	}
	if (!globalData->addObserver(":D", &observer)) {
		std::cout << "No se puede agregar observador para el registro :D." << std::endl;
		return 1;
	}
	if (!globalData->addObserver(":D", &observer)) {
		std::cout << "No se puede agregar observador para el registro :D." << std::endl;
		return 1;
	}
	cnc::base::Register *reg;
	if ((reg = globalData->getRegister(":)")) == 0) {
		std::cout << "No se puede acceder el registro :)." << std::endl;
		return 1;
	} else
		if (!reg->set(static_cast<uint8_t>(8))) {
			std::cout << "No se puede establecer el valor del registro :)." << std::endl;
			return 1;
		}
	if ((reg = globalData->getRegister(":(")) == 0) {
		std::cout << "No se puede acceder el registro :(." << std::endl;
		return 1;
	} else
		if (!reg->set(static_cast<int32_t>(32))) {
			std::cout << "No se puede establecer el valor del registro :(." << std::endl;
			return 1;
		}
	if ((reg = globalData->getRegister(":D")) == 0) {
		std::cout << "No se puede acceder el registro :D." << std::endl;
		return 1;
	} else
		if (!reg->set(static_cast<double>(64))) {
			std::cout << "No se puede establecer el valor del registro :D." << std::endl;
			return 1;
		}
	if ((reg = globalData->getRegister(":)")) == 0) {
		std::cout << "No se puede acceder el registro :)." << std::endl;
		return 1;
	} else
		{
			int8_t error;
			if (!reg->get(&error))
				std::cout << "No se puede leer el dato: "
				"tipo de dato incorrecto para 'error'." << std::endl;
			else
				std::cout << "error = " << error << std::endl;
			uint8_t ok;
			if (!reg->get(&ok))
				std::cout << "No se puede leer el dato: "
				"tipo de dato incorrecto para ok." << std::endl;
			else
				std::cout << "ok = " << static_cast<int>(ok) << std::endl;
		}
	return 0;
}

